package se.webbzon.oschi01.aes;

import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;

public class RijndaelParser implements DataInput {
	
	// The data input stream used to read from the buffer
	private final DataInputStream dis;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public RijndaelParser(byte[] data, int off, int length) {
		if (length % 16 != 0)
			throw new IllegalArgumentException("Data array must be a multiple of 16. Length = " + length);
		int padding = fromUTF8Hex(data[0]);
		ByteBuffer buffer = ByteBuffer.wrap(data, off+1, length-padding-1);
		dis = new DataInputStream(new ByteBufferInputStream(buffer));
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the input stream used to read data from the underlying data content. **/
	public InputStream getInputStream() {
		return dis;
	}
	
	@Override public boolean readBoolean() throws IOException {
		return dis.readBoolean();
	}

	@Override public byte readByte() throws IOException {
		return dis.readByte();
	}

	@Override public char readChar() throws IOException {
		return dis.readChar();
	}

	@Override public double readDouble() throws IOException {
		return dis.readDouble();
	}

	@Override public float readFloat() throws IOException {
		return dis.readFloat();
	}

	@Override public void readFully(byte[] b) throws IOException {
		dis.readFully(b);
	}

	@Override public void readFully(byte[] b, int off, int len) throws IOException {
		dis.readFully(b, off, len);
	}

	@Override public int readInt() throws IOException {
		return dis.readInt();
	}

	@Deprecated @Override public String readLine() throws IOException {
		return dis.readLine();
	}

	@Override public long readLong() throws IOException {
		return dis.readLong();
	}

	@Override public short readShort() throws IOException {
		return dis.readShort();
	}

	@Override public String readUTF() throws IOException {
		return dis.readUTF();
	}

	@Override public int readUnsignedByte() throws IOException {
		return dis.readUnsignedByte();
	}

	@Override public int readUnsignedShort() throws IOException {
		return dis.readUnsignedShort();
	}

	@Override public int skipBytes(int n) throws IOException {
		return dis.skipBytes(n);
	}

	/*============================================================
	Private Methods
	============================================================*/

	/** Returns the value of the hexadecimal character represented
	 * by the UTF-8 character with the given character code. **/
	private static final byte fromUTF8Hex(int i) {
		if (i > 96)
			return  (byte) (i - 87);
		else if (i > 64)
			return  (byte) (i - 55);
		else
			return (byte) (i - 48);
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	/** An output stream used to write into a byte buffer. **/
	private static final class ByteBufferInputStream extends InputStream {
		
		// The byte buffer to write the data into
		private final ByteBuffer buffer;
		
		/*============================================================
		Constructors
		============================================================*/
		
		public ByteBufferInputStream(ByteBuffer buffer) {
			this.buffer = buffer;
		}
		
		/*============================================================
		Public Methods
		============================================================*/
		
		@Override public int read() {
			if (buffer.remaining() == 0)
				return -1;
			else
				return buffer.get();
		}

		@Override public int available() {
			return buffer.remaining();
		}

		@Override public boolean markSupported() {
			return false;
		}

		@Override public int read(byte[] b, int off, int len) {
			int n = Math.min(len, buffer.remaining());
			if (n > 0) {
				buffer.get(b, off, n);
				return n;
			} else
				return -1;
		}

		@Override public long skip(long n) {
			int skip = Math.min((int) n, buffer.remaining());
			buffer.position(buffer.position() + skip);
			return skip;
		}
		
	}
	
}
